package com.hlkj.pay.util;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;

import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import cn.hutool.crypto.symmetric.SM4;


/**
 * @description: SM4对称加密工具类
 * @author:SM2Utils
 * @since:
 */
public class SM4Utils {


    private static final int DEFAULT_KEY_LENGTH = 16;

    private static final String ALL_CHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final String ENCRYPTION_ALGORITHM = "SM4";

    private static final String MODE_CBC = "CBC";

    private static final String PKCS7PADDING = "PKCS7Padding";

    private static final IvParameterSpec sm4IvSpec = new IvParameterSpec(Base64.getDecoder().decode(
            "AQ4Zvt54xKn9QaW86ZzWdg=="));

    private SM4Utils() {
    }

    public static String generateRandomKey() {
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < DEFAULT_KEY_LENGTH; i++) {
            sb.append(ALL_CHAR.charAt(random.nextInt(ALL_CHAR.length())));
        }
        return sb.toString();
    }

    public static String decryptBase64(String message, String sm4Key) {
        return sm4DecryptBase64(message, toSecretKeySpec(sm4Key));
    }

    public static String encryptBase64(String message, String sm4Key) {
        return sm4EncryptBase64(message, toSecretKeySpec(sm4Key));
    }

    public static SecretKeySpec toSecretKeySpec(String sm4Key) {
        return new SecretKeySpec(sm4Key.getBytes(StandardCharsets.UTF_8), ENCRYPTION_ALGORITHM);
    }

    public static String sm4DecryptBase64(String message, SecretKeySpec keySpec) {
        byte[] bytes = Base64.getDecoder().decode(message);
        byte[] decrypted = SM4Utils.decrypt(keySpec, sm4IvSpec, bytes);
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    public static String sm4EncryptBase64(String message, SecretKeySpec keySpec) {
        return encryptBase64(keySpec, sm4IvSpec, message.getBytes(StandardCharsets.UTF_8));
    }


    public static String encryptBase64(SecretKey key, IvParameterSpec iv, byte[] data) {
        byte[] bytes = encrypt(key, iv, data);
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static byte[] encrypt(SecretKey key, IvParameterSpec iv, byte[] data) {
        SM4 sm4 = new SM4(MODE_CBC, PKCS7PADDING, key, iv);
        return sm4.encrypt(data);
    }

    public static byte[] decrypt(SecretKey key, IvParameterSpec iv, byte[] data) {
        SM4 sm4 = new SM4(MODE_CBC, PKCS7PADDING, key, iv);
        return sm4.decrypt(data);
    }


    public static void main(String[] args) {
//        Stopwatch stopwatch = Stopwatch.createStarted();
//        String sm4Key = generateRandomKey();
//        System.out.println("执行时长1:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        String content ="12345678";
//        System.out.println("content length:"+content.length());
//        SecretKeySpec encryptSecretKey = toSecretKeySpec(sm4Key);
//        System.out.println("执行时长2:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        String sm4EncryptBase64 = sm4EncryptBase64(content,encryptSecretKey);
//        System.out.println("执行时长3:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        System.out.println("sm4EncryptBase64:"+sm4EncryptBase64);
//        String encryptSm4Key = SM2Utils.encryptToBase64(HeliPayCertConfig.getMerchantPublicKey(),sm4Key);
//        System.out.println("执行时长4:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        String decryptSm4Key = SM2Utils.decryptBase64Message(HeliPayCertConfig.getMerchantPrivateKey(),encryptSm4Key);
//        System.out.println("执行时长5:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        String sm4DecryptBase64 = decryptBase64(sm4EncryptBase64,decryptSm4Key);
//        System.out.println("执行时长6:"+stopwatch.elapsed(TimeUnit.MILLISECONDS));
//        System.out.println("sm4DecryptBase64:"+sm4DecryptBase64);
    }

}